#ifndef GHOST_H
#define GHOST_H

#include <QObject>
#include <QGraphicsObject>
#include <QPixmap>
#include <QDialog>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QList>
#include <QPainter>
#include <QPropertyAnimation>
#include <QStyle>
#include <QStyleOptionGraphicsItem>
#include "gameanimation.h"
#include "playertable.h"
#include "foregroundscene.h"

class Ghost;
class GhostManager;
class GhostInfo;
class GhostDeck;
class ResistItem;
class ResistItemGroup;
class GhostCard;
class GhostSkillSlot;
class GhostSkillSlotGroup;
class GhostCutIn;
class InputBlocker;
class PlayerTable;


class Ghost : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString imagePath READ getImagePath CONSTANT)
    Q_PROPERTY(QString ghostName READ getName  CONSTANT)
    Q_PROPERTY(int ghostID  READ getID CONSTANT)
    Q_PROPERTY(int resist0  READ getResist0 CONSTANT)
    Q_PROPERTY(int resist1  READ getResist1 CONSTANT)
    Q_PROPERTY(int resist2  READ getResist2 CONSTANT)
    Q_PROPERTY(int resist3  READ getResist3 CONSTANT)
    Q_PROPERTY(int resist4  READ getResist4 CONSTANT)
    Q_PROPERTY(bool boss    READ isBoss CONSTANT)
    Q_PROPERTY(bool movable READ movable CONSTANT)
    Q_PROPERTY(bool buddha  READ killWithBuddha CONSTANT)
    Q_PROPERTY(GhostColor color READ getColor CONSTANT)
    Q_PROPERTY(BaneSkill  skill_l READ getSkillL CONSTANT)
    Q_PROPERTY(BaneSkill  skill_m READ getSkillM CONSTANT)
    Q_PROPERTY(BaneSkill  skill_r READ getSkillR CONSTANT)

    Q_ENUMS(GhostColor)
    Q_ENUMS(BaneSkills)
public:
    enum GhostColor
    {
        RED,
        YELLOW,
        BLUE,
        GREEN,
        BLACK,
        WHITE
    };

    /* There are three possible ghost skills/bane/reward on the card
        (bot left, bot mid, bot right). as the reward for killing a
        ghost may not always be possitive, I merge the reward and the bane
        together.
    */
    enum BaneSkill
    {
        NOTHING = 0,
        ONE_MORE_CARD,
        INSTANT_HAUNT,
        CURSE_DICE,
        GHOSTS_MARCH,
        SEAL_SKILLS,
        DICE_HOLDER,
        LOSE_QI,
        HAUNTER,
        QI_PLUS_YINYANG = 10, // rewards start from 10
        TAO
    };

    Ghost( QObject* parent, // maybe ghost manager
           QString path,
           QString name,
           int id,
           GhostColor color,
           BaneSkill  skill_l,
           BaneSkill  skill_m,
           BaneSkill  skill_r,
           int resist0  = 0,
           int resist1  = 0,
           int resist2  = 0,
           int resist3  = 0,
           int resist4  = 0,
           bool movable = false,
           bool boss    = false,
           bool buddha  = false
           );
    int            getID           () { return _ghostid; }
    int            getResist0      () { return _resist0; }
    int            getResist1      () { return _resist1; }
    int            getResist2      () { return _resist2; }
    int            getResist3      () { return _resist3; }
    int            getResist4      () { return _resist4; }
    BaneSkill      getSkillL       () { return _skill_l; }
    BaneSkill      getSkillM       () { return _skill_m; }
    BaneSkill      getSkillR       () { return _skill_r; }
    GhostColor     getColor        () { return _color; }
    bool           movable         () { return _movable; }
    bool           isBoss          () { return _boss; }
    bool           killWithBuddha  () { return _buddha; }
    QString        getName         () { return _ghostname; }
    QString        getImagePath    () { return _imgpath; }

    static QString ColorToString ( GhostColor c );
    static Qt::GlobalColor ColorToQColor ( GhostColor c );
    static QString SkillToString ( BaneSkill s );
private:
    QString       _imgpath;
    QString       _ghostname;
    int           _ghostid;
    GhostColor    _color;
    BaneSkill     _skill_l;
    BaneSkill     _skill_m;
    BaneSkill     _skill_r;
    int           _resist0;
    int           _resist1;
    int           _resist2;
    int           _resist3;
    int           _resist4;
    bool          _movable;
    bool          _boss;
    bool          _buddha;

};

/* class GhostManager */
/*
    This class is a manager for ghosts
    It stores all ghosts informations and some facilities to manipulate them;
    It may generate a deck of ghost cards for playing with a certain pattern;
    other functionalities are under further consideration.
*/

class GhostManager : public QObject
{
    Q_OBJECT
public:
    GhostManager( QObject* parent = 0 );
    void add( Ghost* ghost );
    QList <Ghost*> getDeck( int rounds, int trash, bool shuffle = true );
    static QList <Ghost*> TestDeck();
    static Ghost* DefaultGhost();
private:
    int _ghostcount;
    QList <Ghost*> _tglist; // trash ghosts list
    QList <Ghost*> _bglist; // boss ghosts list
};


/* class GhostInfoGraphics */
/*
   An alternative to GhostInfo class. This class creates a ghost information
   as a QGraphicsObject, which provides a more compact view of a ghost card.
*/

class GhostInfo : public QGraphicsObject
{
    Q_OBJECT

public:
    GhostInfo( QGraphicsObject* parent = 0 );
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    Ghost* currentGhost();
    int width()  { return INFO_WIDTH;  }
    int height() { return INFO_HEIGHT; }
public slots:
    void setGhost( Ghost* ghost );
protected slots:
    void fadeFinished();
signals:
    void ghostChanged();
protected:
    QPixmap _bg;
    Ghost* _dghost, *_ghost;
    QList <Ghost*> _testdeck;
    GhostCard*  _carditem;
    GhostSkillSlotGroup* _skillitem;
    ResistItemGroup*     _resistitem;
    QFont _font;
    QPropertyAnimation *_anim_card0, *_anim_card1;
    int _clickcount;
    int INFO_WIDTH;
    int INFO_HEIGHT;
};


/*
    A simple implementation of ghost card deck by
    re-using the GhostInfo class.
*/
class GhostDeck : public GhostInfo
{
    Q_OBJECT
public:
    GhostDeck( QGraphicsObject* parent = 0, GhostInfo *ginfo = 0, PlayerTable *ptable = 0 );
    void   flip();
    Ghost* pop();
    void   newDeck();
    void   setGhostInfo( GhostInfo *ginfo ) { _ginfo = ginfo; }
    void   setPlayerTable( PlayerTable *ptable ) { _ptable = ptable; }
public slots:
    void   clicked();
    void   hover_in();
    void   hover_out();
signals:
    void bossInvoked();
private:
    QList <Ghost*> _deck;
    bool _fliped;
    GhostInfo* _ginfo;
    PlayerTable* _ptable;
};


/* Ghost card QGraphicsObject */
class GhostCard : public QGraphicsObject
{
    Q_OBJECT

public:
    GhostCard( QGraphicsObject* parent = 0 );
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void setGhost( Ghost *ghost );
    int width() { return _width; }
    int height() { return _height; }
protected:
    void mousePressEvent( QGraphicsSceneMouseEvent *event )
    {
        emit clicked();
    }
    void hoverEnterEvent( QGraphicsSceneHoverEvent *event )
    {
        emit hover_entered();
    }

    void hoverLeaveEvent( QGraphicsSceneHoverEvent *event )
    {
        emit hover_left();
    }

signals:
    void clicked();
    void hover_entered();
    void hover_left();
private:
    Ghost *_ghost;
    QPixmap _qpcard, _qpbg;
    QPixmap _qpboss;
    QPixmap _rib0, _rib1, _rib2, _rib3, _rib4;
    Qt::GlobalColor _color;
    int _width, _height, _cwidth, _cheight;
    qreal _scale;
};


/* Ghost skill slot QGraphicsObject */
class GhostSkillSlot : public QGraphicsObject
{
    Q_OBJECT
public:
    GhostSkillSlot( QGraphicsObject* parent = 0 );
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void setSkill( Ghost::BaneSkill skill );
    static QPixmap SkillQPixmap( Ghost::BaneSkill skill );
    int _w, _h;
private:
    Ghost::BaneSkill _skill;
    QPixmap _bg, _qpskill;
    int _iconw, _iconh;
};

/* Ghost skill slot QGraphicsObject (for grouping the skills) */
class GhostSkillSlotGroup : public QGraphicsObject
{
    Q_OBJECT
public:
    GhostSkillSlotGroup( QGraphicsObject* parent = 0 );
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void setGhost( Ghost* ghost );
private:
    Ghost* _ghost;
    GhostSkillSlot *_skill_slot_l;
    GhostSkillSlot *_skill_slot_m;
    GhostSkillSlot *_skill_slot_r;
    int _w, _h;
    const static int HGAP = 20;
};


/* Ghost resistance QGraphicsObject */
class ResistItem : public QGraphicsObject
{
    Q_OBJECT

public:
    ResistItem( QGraphicsObject *parent = 0  );
    QRectF boundingRect() const { return QRectF( -_w/2, -_h/2, _w, _h ); }
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

    void setResistance( QPixmap pixmap ) { _qp = pixmap; _null = false; }

    void setNull( )
    {
        _null = true;
        _anim_0->stop();
        _anim_1->stop();
        _anim_2->stop();
        _anim_group_0->stop();
        _anim_group_1->stop();
    }

public slots:
    void animate() { if( !_null ) _anim_group_1->start(); }
    void half_slot() { emit half_finished(); }
signals:
    void half_finished();
    void manual_stop();
private:
    QPixmap _qp;
    bool _null;
    QPropertyAnimation *_anim_0, *_anim_1, *_anim_2;
    QSequentialAnimationGroup *_anim_group_0;
    QParallelAnimationGroup *_anim_group_1;
    const static int _w = 25, _h = 40;
};


/* Ghost resistances QGraphicsObjects (manage the group of resistances) */
class ResistItemGroup : public QGraphicsObject
{
    Q_OBJECT

public:
    ResistItemGroup( QGraphicsObject *parent = 0, Ghost* ghost = 0  );
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void setGhost( Ghost* ghost );
public slots:
    void updateState();
private:
    int _resist0;
    int _resist1;
    int _resist2;
    int _resist3;
    int _resist4;
    int _total_resist;
    QList <ResistItem*> _items;
    const static int _hgap = -10, _vgap = 2;
    QPixmap _qp0, _qp1, _qp2, _qp3, _qp4;
};


class GhostCutIn : public QGraphicsObject
{
    Q_OBJECT
public:
    GhostCutIn( QGraphicsItem *parent = 0, GhostInfo* ghostinfo = 0, InputBlocker* blocker = 0 );
    void setGhost( Ghost* ghost );
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
public slots:
    void animate();
    void animate_finished();
signals:
    void cutin_finished();
private:
    int _w, _h, _cw, _ch;
    QPixmap _bg, _qpcard;
    Ghost* _ghost;
    GhostInfo* _ginfo;
    GameParAnimation *_anim_group_1, *_anim_group_2, *_anim_group_3;
    GameSeqAnimation *_anim_group_0;
    QFont _font;
};

class GhostPixmap : public QGraphicsObject
{
    Q_OBJECT
public:
    GhostPixmap(QGraphicsObject* parent)
        : QGraphicsObject(parent), slotUse(false)
    {
        setVisible(false);
    }
    QRectF boundingRect() const{return QRectF(-_pix.width()/2, -_pix.height()/2, _pix.width(), _pix.height());}
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    void setPixmap(QPixmap pix){_pix = pix; setVisible(true);}
    void scaleForSlotUse(bool b){slotUse = b;}
protected:
    QPixmap _pix;
    bool slotUse;
};

#endif // GHOST_H
